package com.night.icm.service.business.service;

import com.night.icm.common.utils.OcrAndPdfUtil;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * FileStorageServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/3/8
 */
@Service
@Slf4j
public class FileStorageServiceImpl implements FileStorageService {


    private static final int BUFFER_SIZE = 8192;
    private static final String FILE_TYPE = ".txt";
    private static final String TESS_DATA = "chi_sim";
    private String fileDir;
    private String tempDir;

    @Autowired
    public FileStorageServiceImpl(@Value("${night.framework.upload.temp-path}") String tempPath,
                                  @Value("${night.framework.upload.file-path}") String filePath) {
        this.fileDir = filePath;
        this.tempDir = tempPath;
        try {
            FileUtils.forceMkdir(new File(fileDir));
            FileUtils.forceMkdir(new File(tempDir));
        } catch (IOException e) {
            log.warn(e.getMessage());
        }
    }

    /**
     * 保存一个文件。保存时，系统会自动移除时间戳，并重新生成一个内部文件名，也可称为文件的key，取文件时，需要使用此值。
     *
     * @param file 要保存的文件,
     * @return 文件的key, 可以通过该key取回文件
     * @throws IOException 保存失败则抛出异常
     */
    @Override
    public String save(File file) throws IOException {
        String fileName = UUID.randomUUID().toString();
        String fullPath = fileDir + fileName;

        try (FileInputStream fis = new FileInputStream(file);
             BufferedInputStream source = new BufferedInputStream(fis);
             FileOutputStream fos = new FileOutputStream(fullPath);
             ZipOutputStream dest = new ZipOutputStream(fos)
        ) {

            byte[] buffer = new byte[BUFFER_SIZE];
            ZipEntry zipEntry = new ZipEntry(file.getName());
            dest.putNextEntry(zipEntry);
            int count;
            while ((count = source.read(buffer, 0, BUFFER_SIZE)) != -1) {
                dest.write(buffer, 0, count);
            }
            dest.flush();
            dest.finish();
            return fileName;
        }
    }

    /**
     * 通过Key来找回之前保存的文件
     *
     * @param fileKey 保存时返回的key
     * @return 如果文件存在，则返回文件
     * @throws IOException 无法找到文件或失败则抛出异常
     */
    @Override
    public File get(String fileKey) throws IOException {
        String fileName = fileDir + fileKey;
        String destFile = tempDir + fileKey;
        try (FileInputStream fis = new FileInputStream(fileName);
             ZipInputStream zin = new ZipInputStream(new BufferedInputStream(fis))
        ) {
            ZipEntry entry;

            byte[] buffer = new byte[BUFFER_SIZE];
            while ((entry = zin.getNextEntry()) != null) {
                destFile = tempDir + entry.getName();
                try (FileOutputStream fos = new FileOutputStream(destFile);
                     BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)
                ) {
                    int count;
                    while ((count = zin.read(buffer, 0, BUFFER_SIZE)) != -1) {
                        dest.write(buffer, 0, count);
                    }
                    dest.flush();
                }
            }

            return new File(destFile);
        }
    }

    /**
     * 删除保存的文件
     *
     * @param fileKey 文件的key
     */
    @Override
    public void delete(String fileKey) {
        FileUtils.deleteQuietly(new File(fileDir + fileKey));
        FileUtils.deleteQuietly(new File(tempDir + fileKey));
    }

    /**
     * 识别图片或pdf文件转成txt文件
     *
     * @param resourceFile 图片或pdf文件
     * @return File
     * @throws IOException        无法找到文件或失败则抛出异常
     * @throws TesseractException 图片识别错误抛出异常
     */
    @Override
    public File getTxtFile(File resourceFile) throws IOException, TesseractException {
        String fileName = FilenameUtils.getBaseName(resourceFile.getName());
        String fullPath = tempDir + fileName + FILE_TYPE;
        File txtFile = new File(fullPath);
        return OcrAndPdfUtil.ocrOrPdfService(resourceFile, txtFile, TESS_DATA);
    }
}